/**
 * @class   wosh::entertainment::MediaZone
 * @brief   Represent a multimedia zone, zones are hierarchical.
 *          Zones are managed by wosh::services::MediaDirectorBundle.
 *
 * MediaZone is an high-level interface for controlling multi-zone multimedia, indeed
 * it is strictly related to available devices.
 * Let's device \c "multimedia device" as a wosh::Device object which implements
 * at least one of the following interfaces:
 *  - wosh::interfaces::devices::PlayerAudio
 *  - wosh::interfaces::devices::PlayerVideo
 *
 * MediaZone holds information about a generic multimedia-enganged location,
 * zones may be defined statically or created/updated dynamically (by MediaDirector).
 *
 * A MediaZone is defined if any of following occurs:
 *  - user-defined (statically)
 *  - a generic multimedia device defines its own MediaZone
 *  - a generic wosh::building::Room, equipped with one or more multimedia devices,
 *    will group child-zones (devices)
 *  - a generic wosh::building::Floor, when it has one or more multimedia rooms,
 *    will group child-zones (rooms)
 *  - the whole wosh::building::House
 *
 * Most important features of wosh::entertainment::MediaZone, supported by
 * wosh::services::MediaDirectorBundle are:
 *  - high-level control (naming, grouping/structure, methods)
 *  - synchronization of more zones, devices
 *  - device direct-mapping (map device-events to a multimedia actions)
 *  - persistence (save, load current 'scenario')
 *  - multimedia mobility (music follows you)
 *  - amazing effects (guessing, restoring, random scenario)
 *
 *
					?	wosh.Bus.Media
					?	FARLA TIPO BUILDINGOBJECT???? ha parecchi vantaggi!
 *
 *
 *
 ****************************************************************************
 * @version $Id: MediaZone.h 2863 2010-08-07 04:28:58Z alex $
 * @author  Alessandro Polo
 ****************************************************************************/
/* Copyright (c) 2007-2010, WOSH - Wide Open Smart Home 
 * by Alessandro Polo - OpenSmartHome.com
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the OpenSmartHome.com WOSH nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY Alessandro Polo ''AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL Alessandro Polo BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 ****************************************************************************/

#ifndef __WOSH_Entertainment_MediaZone_H__
 #define __WOSH_Entertainment_MediaZone_H__

 #include <woshDefs.h>
 #include <core/Object.h>
 #include <core/Containers.h>
 #include <core/PropertiesProvider.h>
 #include <core/InterfacesProvider.h>

 #include <framework/entertainment/MediaList.h>


namespace wosh {
 template <class T> class DataFieldCollector;
 namespace entertainment {

 #define _MediaZone_KEY_VolumeDefault		"VolumeDefault"
 #define _MediaZone_KEY_VolumeMin			"VolumeMin"
 #define _MediaZone_KEY_VolumeMax			"VolumeMax"

 #define _MediaZone_KEY_VolumeMuted			"VolumeMuted"
 #define _MediaZone_KEY_VolumeCurrent		"VolumeCurrent"

 #define _MediaZone_KEY_ZoneType			"ZoneType"
 #define _MediaZone_KEY_ZoneRole			"ZoneRole"

 #define _MediaZone_KEY_ZoneRanking			"ZoneRanking"

 #define _MediaZone_METHOD_get_mappings		"get_mappings"
 #define _MediaZone_METHOD_get_medialist	"get_medialist"


class MediaZone : public wosh::Object
 {
	WOSH_SERIALIZABLE(wosh::entertainment::MediaZone)
	WOSH_COMPARE_RTTI(wosh::entertainment::MediaZone)


	public:
		/// zone type, evaluated by MediaDirector within zone update/creation
		enum ZONE_TYPE {
			TYPE_UNKNOWN	= 0x00,	///< undefined mode
			TYPE_STATIC		= 0x01,	///< static mode, zone won't be updated, neither timeout
			TYPE_DYNAMIC	= 0x02,	///< dynamic mode, zone is updated/created/deleted by the system
			TYPE_MIXED		= 0x03	///< as dynamic, but zone won't be removed and some fields are constant
		 };
		/// role of the zone
		enum ZONE_ROLE {
			ROLE_UNKNOWN	= 0x00,	///< undefined role
			ROLE_MASTER		= 0x01,	///< master, highest priority
			ROLE_SLAVE		= 0x02,	///< slave, low priority
			ROLE_FORK		= 0x03	///< fork, slave switching to independent zone
		 };
	public:
		/// multimedia actions, directly mapped to device-events, argument and functionality is evaluated
		/// by MediaDirector
		enum PLAYER_COMMAND {
			COMMAND_UNKNOWN	= 0x00,	///< undefined command
			COMMAND_PLAY	= 0x01,	///< play/stop command (play,restore/move,stop)
			COMMAND_TRACK	= 0x02,	///< track control (first,prev,next,last)
			COMMAND_VOLUME	= 0x04	///< volume control (mute,unmute,higher,lower)
		 };

	public:
		/**
		 * @brief   Default constructor. Init vars.
		 */
		MediaZone();
		/**
		 * @brief  Copy constructor.
		 * @param m [in] the source object to be copied
		 */
		MediaZone( const MediaZone& m );
		/**
		 * @brief  Empty destructor.
		 */
		virtual ~MediaZone() { }

	public:
		virtual void clear();


/** @name Setters
 * @{
 ******************************************************************************/
	public:
		void setSeen()									{ this->timestamp = Utilities::std_time(); }
		void setZoneType( MediaZone::ZONE_TYPE type );
		void setZoneRole( MediaZone::ZONE_ROLE role );
		void setRanking( double value );

		void setParent( const std::string& value );

		void setPlayerURI( const wosh::URI& value )		{ this->playerUri = value; }

		void setLocationURI( const std::string& value )	{ this->locationUri = value; }

		void setVolume( int value );
		void setMuted( bool value );

		virtual void setName( const std::string& value );

//@}
/** @name Getters
 * @{
 ******************************************************************************/
	public:
		inline long getSeen() const							{ return this->timestamp; }

		inline MediaZone::ZONE_TYPE getZoneType() const		{ return this->zoneType; }
		inline std::string getZoneTypeAsString() const		{ return getZoneTypeAsString(this->zoneType); }

		inline double getRanking() const					{ return this->ranking; }

		inline bool isTypeStatic() const					{ return (this->zoneType == MediaZone::TYPE_STATIC); }
		inline bool isTypeDynamic() const					{ return (this->zoneType == MediaZone::TYPE_DYNAMIC); }

		inline MediaZone::ZONE_ROLE getZoneRole() const		{ return this->zoneRole; }
		inline std::string getZoneRoleAsString() const		{ return getZoneRoleAsString(this->zoneRole); }

		inline bool isRoleMaster() const					{ return (this->zoneRole == MediaZone::ROLE_MASTER); }
		inline bool isRoleSlave() const						{ return (this->zoneRole == MediaZone::ROLE_SLAVE); }

		inline const std::string& getParent() const			{ return this->parent; }
		inline std::string& getParent()						{ return this->parent; }

		inline const std::map<std::string,std::string>& getChildren() const	{ return this->children; }
		inline std::map<std::string,std::string>& getChildren()				{ return this->children; }

	public:
		inline const std::string& getLocationURI() const		{ return this->locationUri; }
		inline std::string& getLocationURI()					{ return this->locationUri; }

		inline const URI& getPlayerURI() const					{ return this->playerUri; }
		inline URI& getPlayerURI()								{ return this->playerUri; }

		inline const InterfacesProvider& getInterfaces() const	{ return this->playerIProv; }
		inline InterfacesProvider& getInterfaces()				{ return this->playerIProv; }

		inline const MapT<URI, int>& getKeyMappings() const		{ return this->keyMappings; }
		inline MapT<URI, int>& getKeyMappings()					{ return this->keyMappings; }

		Table* getKeyMappingsAsTable() const;

		inline int getVolumeCurrent() const					{ return this->volumeCurrent; }
		inline int getVolumeDefault() const					{ return Properties.getValueOf(_MediaZone_KEY_VolumeDefault).toInteger(30); }
		inline int getVolumeMin() const						{ return Properties.getValueOf(_MediaZone_KEY_VolumeMin).toInteger(0); }
		inline int getVolumeMax() const						{ return Properties.getValueOf(_MediaZone_KEY_VolumeMax).toInteger(100); }

	public:
		inline const MediaList& getPlayList() const			{ return this->playlist; }
		inline MediaList& getPlayList()						{ return this->playlist; }
 
		inline bool isPlaying() const {
			return ( this->playlist.getCurrentIndex() > 0 ) && ( this->playlist.getCurrentIndex() < this->playlist.size() );
		 }

	public:
		const PropertiesProvider& getProperties() const		{ return this->Properties; }
		PropertiesProvider& getProperties()					{ return this->Properties; }

		static std::string getCommandAsString( int value );
		static int getCommandFromString( const std::string& value );

		static MediaZone::ZONE_TYPE getZoneTypeFromString( const std::string& zoneType );
		static std::string getZoneTypeAsString( MediaZone::ZONE_TYPE zoneType );

		static MediaZone::ZONE_ROLE getZoneRoleFromString( const std::string& zoneRole );
		static std::string getZoneRoleAsString( MediaZone::ZONE_ROLE zoneRole );

		static DataFieldCollector<MediaZone>* getDataFields();

//@}
/** @name Operators Overloading
 * @{
 ******************************************************************************/
	public:
		virtual MediaZone& operator=(const MediaZone& m);
		virtual bool operator==(const MediaZone &other) const;
//@}
/** @name Serialization interface
 * @{
 ******************************************************************************/
	public:
		virtual std::string toString() const			{ return ""; }
		virtual bool updateHash( DataHashContext* hash_context ) const;
//@}
/** @name Internal vars
 * @{
 ******************************************************************************/
	protected:
		long id;						///< unique id of the zone
		long timestamp;					///< timestamp of last update
		MediaZone::ZONE_TYPE zoneType;	///< zone type
		MediaZone::ZONE_ROLE zoneRole;	///< zone role (against current playlist)
		double ranking;					///< ranking of the zone (how frequently it is used)

		std::string parent;				///< parent MediaZone
		std::map<std::string,std::string> children; ///< child MediaZones

		std::string locationUri; 		///< UserInfoLocation.location

	protected:
		URI playerUri;					///< reference device
		InterfacesProvider playerIProv;	///< supported interfaces

		bool volumeMuted;
		int volumeCurrent;				///< current volume [0,100]. default = -1

		MapT<URI, int> keyMappings;	///< key mapping! [device->Action]


	protected:
		MediaList playlist;				///< the current playlist, not inherited by children!

		PropertiesProvider Properties;	///< zone properties

//@}


}; // class def

 }; // namespace entertainment
}; // namespace wosh


#endif //__WOSH_Entertainment_MediaZone_H__
